home *** CD-ROM | disk | FTP | other *** search
/ PC User 2003 January / Disc 1 / PCU0103CD1.iso / entertn / demos / files / aomtrial.exe / AOM / AI / SCN35P3.XS < prev    next >
Encoding:
Text File  |  2002-08-20  |  19.8 KB  |  532 lines

  1. //==============================================================================
  2. // Scn35p3: AI Scenario Script for scenario 35 player 3
  3. //==============================================================================
  4. /*
  5.    AI owner:  Dave Leary
  6.    Scenario owner: Joe Gillum
  7.  
  8.    Basic AI to set villagers working and do some basic maintaining and scouting
  9.     for the HP's Norse ally in the final scenario.
  10.         
  11. */
  12. //==============================================================================
  13. // Variable for main base.
  14. int gMainBaseID=-1;
  15.  
  16. //==============================================================================
  17. // Set Town Location
  18. //==============================================================================
  19. void setTownLocation(void)
  20. {
  21.    //Look for the "Town Location" marker.
  22.    kbSetTownLocation(kbGetBlockPosition("2928"));
  23. }
  24.  
  25. //==============================================================================
  26. // miscStartup
  27. //==============================================================================
  28. void miscStartup(void)
  29. {
  30.     // Difficulty Level check.
  31.     int difflevel=-1;        
  32.     difflevel=aiGetWorldDifficulty();
  33.  
  34.    //Startup message(s).
  35.    aiEcho("");
  36.    aiEcho("");
  37.    aiEcho("Scn35P3 AI Start, filename='"+cFilename+"'.");
  38.     aiEcho("Difficulty Level="+difflevel+".");
  39.    //Spit out the map size.
  40.    aiEcho("  Map size is ("+kbGetMapXSize()+", "+kbGetMapZSize()+").");
  41.    //Cheat like a bastard.  Once only, though.
  42.    kbLookAtAllUnitsOnMap();
  43.    //Calculate some areas.
  44.    kbAreaCalculate(1200.0);
  45.    //Set our town location.
  46.    setTownLocation();
  47.     //Reset random seed
  48.     aiRandSetSeed();
  49.  
  50.     //Set the base location.
  51.     gMainBaseID=kbBaseGetMainID(cMyID);
  52. }
  53.  
  54. //==============================================================================
  55. //==============================================================================
  56. // Attack stuff.
  57. //==============================================================================
  58. //==============================================================================
  59. //Shared variables.
  60. int numberAttacks=0;
  61. int attackPlayerID=-1;
  62.  
  63. //TODO: Decide how to rep attack group size.
  64. int attackMinimumGroupSize=3;
  65. int attackMaximumGroupSize=5;
  66.  
  67. //Attack 1 vars.
  68. int attackPlan1ID=-1;
  69.  
  70. //Attack 2 vars.
  71. int attackPlan2ID=-1;
  72.  
  73. // Route and path vars
  74. int attackRoute1ID=-1;
  75. int attackPath1ID=-1;
  76. int attackRoute2ID=-1;
  77. int attackPath2ID=-1;
  78.  
  79. // Saved plan IDs
  80. int maintainPlan1ID=-1;
  81. int maintainPlan2ID=-1;
  82. int maintainPlan3ID=-1;
  83. int maintainPlan4ID=-1;
  84.  
  85. // Unit types
  86. int attackerUnitTypeID1=cUnitTypeVillagerNorse;
  87. int attackerUnitTypeID2=cUnitTypeUlfsark;
  88. int attackerUnitTypeID3=cUnitTypeRaidingCavalry;
  89. int attackerUnitTypeID4=cUnitTypeMountainGiant;
  90.  
  91. // Initial gather percentages
  92. float totalFoodGathererPercentage  = 0.6;
  93. float totalWoodGathererPercentage  = 0.4;
  94. float totalGoldGathererPercentage  = 0.0;
  95. float totalFavorGathererPercentage = 0.0;
  96.  
  97.  
  98. //==============================================================================
  99. // initEcon
  100. //
  101. // Set Up the initial Econonomy.
  102. //==============================================================================
  103. void initEcon()
  104. {
  105.    aiEcho("Economy Init.");
  106.  
  107.     /* Don't need this for what we're doing here.
  108.    // Set our update resource handler.
  109.    aiSetUpdateResourceEventHandler("updateResourceHandler");
  110.     */
  111.  
  112.    //-- Setup AI Cost weights.
  113.    kbSetAICostWeight(cResourceFood, 1.5);
  114.    kbSetAICostWeight(cResourceWood, 1.0);
  115.    kbSetAICostWeight(cResourceGold, 1.5);
  116.    kbSetAICostWeight(cResourceFavor, 10.0);
  117.  
  118.    //-- Dont auto gather favor
  119.    //totalFavorGathererPercentage = 0;
  120.  
  121.    //-- Set initial gatherer percentages.
  122.    aiSetResourceGathererPercentage(cResourceFood, totalFoodGathererPercentage, false, cRGPScript);
  123.    aiSetResourceGathererPercentage(cResourceWood, totalWoodGathererPercentage, false, cRGPScript);
  124.    aiSetResourceGathererPercentage(cResourceGold, totalGoldGathererPercentage, false, cRGPScript);
  125.    aiSetResourceGathererPercentage(cResourceFavor, totalFavorGathererPercentage, false, cRGPScript);
  126.    aiNormalizeResourceGathererPercentages(cRGPScript);
  127.  
  128.    //-- Set up the initial resource subtype break downs.
  129.     // aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, 1, 50, 0.9, gMainBaseID);
  130.     // aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHunt, 1, 50, 0.1, gMainBaseID);
  131.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 50, 1.0, gMainBaseID);
  132.     aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  133.     aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  134.    aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, 1, 50, 1.0, gMainBaseID);
  135.     
  136.    //-- Set up auto-gather escrows
  137.    aiSetAutoGatherEscrowID(cRootEscrowID);
  138.    aiSetAutoFarmEscrowID(cRootEscrowID);
  139.  
  140.     //Allocate all resources to the root escrow by setting percentage of military/economy to 0.
  141.     kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0 );
  142.     kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0 );
  143.  
  144.     //-- create a herd plan to gather all herdables that we ecounter.
  145.     /*
  146.    int herdPlanID=aiPlanCreate("HerdTest", cPlanHerd);
  147.    if (herdPlanID >= 0)
  148.    {
  149.       aiPlanAddUnitType(herdPlanID, cUnitTypeHerdable, 0, 100, 100);
  150.       aiPlanSetVariableInt(herdPlanID, cHerdPlanBuildingTypeID, 0, cUnitTypeSettlementLevel1);
  151.       aiPlanSetActive(herdPlanID);
  152.    }
  153.     */
  154.  
  155.     //Allocate all resources
  156.    kbEscrowAllocateCurrentResources();
  157. }
  158.  
  159. //==============================================================================
  160. // initAttack: Creates attack routes, etc.
  161. //==============================================================================
  162. void initAttack(int playerID=-1)
  163. {
  164.    //Destroy all previous attacks (if this isn't the player we're already attacking.
  165.    if (playerID != attackPlayerID)
  166.    {
  167.       //Reset the attack player ID.
  168.       attackPlayerID=-1;
  169.       //Destroy any previous attack plan.
  170.       aiPlanDestroy(attackPlan1ID);
  171.       attackPlan1ID=-1;
  172.       aiPlanDestroy(attackPlan2ID);
  173.       attackPlan2ID=-1;
  174.   
  175.       //Destroy our previous attack paths.
  176.       kbPathDestroy(attackPath1ID);
  177.       attackPath1ID=-1;
  178.       kbPathDestroy(attackPath2ID);
  179.       attackPath2ID=-1;
  180.  
  181.       //Destroy our previous attack routes.
  182.       attackRoute1ID=-1;
  183.       attackRoute2ID=-1;
  184.  
  185.       //Reset the number of attacks.
  186.       numberAttacks=0;
  187.    }
  188.  
  189.    //Save the player to attack.
  190.    attackPlayerID=playerID;
  191.  
  192.     /*
  193.  
  194.    vector gatherPoint=kbGetBlockPosition("3102");
  195.        
  196.     //Setup attack path 1 - go left
  197.    attackPath1ID=kbPathCreate("Attack Path 1");
  198.    kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3990"));
  199.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3991"));
  200.     kbPathAddWaypoint(attackPath1ID, kbGetBlockPosition("3992"));
  201.    //Create attack route 1.
  202.    attackRoute1ID=kbCreateAttackRouteWithPath("Attack Route 1", gatherPoint, kbGetBlockPosition("3995"));
  203.    
  204.     if (attackRoute1ID >= 0)
  205.       kbAttackRouteAddPath(attackRoute1ID, attackPath1ID);
  206.  
  207.    //Setup attack path 2 - go right
  208.    attackPath2ID=kbPathCreate("Attack Path 2");
  209.    kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3990"));
  210.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3991"));
  211.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3993"));
  212.     kbPathAddWaypoint(attackPath2ID, kbGetBlockPosition("3994"));
  213.    //Create attack route 2.
  214.    attackRoute2ID=kbCreateAttackRouteWithPath("Attack Route 2", gatherPoint, kbGetBlockPosition("3995"));
  215.    
  216.     if (attackRoute2ID >= 0)
  217.       kbAttackRouteAddPath(attackRoute2ID, attackPath2ID);
  218.     */
  219. }
  220.  
  221. //==============================================================================
  222. // setupAttack
  223. //==============================================================================
  224. bool setupAttack(int playerID=-1)
  225. {
  226.    
  227.     //Info.
  228.     aiEcho("Attacking Player "+playerID+".");
  229.  
  230.    //If the player to attack doesn't match, init the attack.
  231.    if (attackPlayerID != playerID)
  232.    {
  233.       initAttack(playerID);
  234.       if (attackPlayerID < 0)
  235.          return(false);
  236.    }
  237.  
  238.    //Create an attack plan.
  239.    int newAttackPlanID=aiPlanCreate("Attack Player"+attackPlayerID+" Attempt"+numberAttacks, cPlanAttack);
  240.    if (newAttackPlanID < 0)
  241.       return(false);
  242.  
  243.    //Target player (required).  This must work.
  244.    if (aiPlanSetVariableInt(newAttackPlanID, cAttackPlanPlayerID, 0, attackPlayerID) == false)
  245.       return(false);
  246.  
  247.    //Gather point.
  248.     vector gatherPoint=kbGetBlockPosition("3127");
  249.  
  250.     //Set the target type.  This must work.
  251.    if (aiPlanSetNumberVariableValues(newAttackPlanID, cAttackPlanTargetTypeID, 2, true) == false)
  252.       return(false);
  253.  
  254.    //Unit types to attack.
  255.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  256.     aiPlanSetVariableInt(newAttackPlanID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  257.  
  258.    //Attack route.
  259.     /*
  260.    if (randomPath == 0)
  261.     {
  262.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute1ID);
  263.     }
  264.    else
  265.     {
  266.       aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRouteID, 0, attackRoute2ID);
  267.     }
  268.     */
  269.  
  270.    //Set the gather point and gather point distance.
  271.    aiPlanSetVariableVector(newAttackPlanID, cAttackPlanGatherPoint, 0, gatherPoint);
  272.    aiPlanSetVariableFloat(newAttackPlanID, cAttackPlanGatherDistance, 0, 40.0);
  273.  
  274.    //Set up the attack route usage pattern.
  275.    aiPlanSetVariableInt(newAttackPlanID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternRandom);
  276.    
  277.     //Add the unit types to the plan - cav...
  278.    aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID3, 4, 4, 8);
  279.     //...and ulfsarks...
  280.     aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID2, 0, 2, 6);
  281.     // ...and a single mountain giant, if available.
  282.     aiPlanAddUnitType(newAttackPlanID, attackerUnitTypeID4, 0, 1, 1);
  283.     
  284.    //Set the initial position.
  285.    aiPlanSetInitialPosition(newAttackPlanID, gatherPoint);
  286.    //Plan requires all need units to work (can be false).
  287.    aiPlanSetRequiresAllNeedUnits(newAttackPlanID, true);
  288.    //Activate the plan.
  289.    aiPlanSetActive(newAttackPlanID);
  290.  
  291.    //Now, save the attack plan ID appropriately.
  292.    aiPlanSetOrphan(attackPlan1ID, true);
  293.    attackPlan1ID=newAttackPlanID;
  294.  
  295.    //Increment our overall number of attacks.
  296.    numberAttacks++;
  297. }
  298.  
  299. //==============================================================================
  300. // createUnitProgression
  301. //==============================================================================
  302. int createUnitProgression(int unitTypeID=-1, string name="BUG")
  303. {
  304.    int pID=aiPlanCreate(name, cPlanProgression);
  305.    
  306.     if (pID < 0)
  307.       return(-1);
  308.  
  309.    //This is a military plan.
  310.    //aiPlanSetMilitary(pID, true);
  311.    //Set it for the building that we get our unit from.
  312.    aiPlanSetVariableInt(pID, cProgressionPlanGoalUnitID, 0, kbTechTreeGetUnitIDByTrain(unitTypeID));
  313.    
  314.     //Build it in our main base using the root escrow.
  315.     aiPlanSetBaseID(pID, gMainBaseID);
  316.     aiPlanSetEscrowID(pID, cRootEscrowID);
  317.    
  318.     //Go.
  319.    aiPlanSetActive(pID);
  320.    return(pID);
  321. }
  322.  
  323. //==============================================================================
  324. // createTechProgression
  325. //==============================================================================
  326. int createTechProgression(int techID=-1, string name="BUG", int researchFromProto=-1)
  327. {
  328.    //Check for old plan.
  329.     int oldPlanID=aiPlanGetIDByTypeAndVariableType(cPlanProgression, cProgressionPlanGoalTechID, techID);
  330.    if(oldPlanID != -1)
  331.    {
  332.       aiEcho("createTechProgression: already have a plan("+oldPlanID+") for this Tech("+techID+").");
  333.       return(oldPlanID);
  334.    }
  335.    
  336.     //Create a new one.
  337.    int pID=aiPlanCreate(name, cPlanProgression);
  338.    if (pID < 0)
  339.    {
  340.       aiEcho("createTechProgression: couldn't create Progression.");
  341.       return(-1);
  342.    }
  343.    //This is a military plan.
  344.    //aiPlanSetMilitary(pID, true);
  345.    aiPlanSetVariableInt(pID, cProgressionPlanGoalTechID, 0, techID);
  346.    aiPlanSetVariableInt(pID, cProgressionPlanBuildingPref, 0, researchFromProto);
  347.    
  348.     //Build it in our main base using the root escrow.
  349.    aiPlanSetBaseID(pID, gMainBaseID);
  350.     aiPlanSetEscrowID(pID, cRootEscrowID);
  351.  
  352.    //Go.
  353.    aiPlanSetActive(pID);
  354.    aiEcho("createTechProgression: creating Tech Progression("+name+") to TechID("+techID+").");
  355.    return(pID);
  356. }
  357.  
  358. //==============================================================================
  359. // Attack Generator 1 - Send dudes now!  Or, well, soon.
  360. //==============================================================================
  361.  
  362. rule attackGenerator1
  363.    minInterval 90
  364.    inactive
  365.    group AttackRules
  366. {
  367.    //See how many "idle" attack plans we have.  Don't create any more if we have
  368.    //idle plans.
  369.    int numberIdleAttackPlans=aiGetNumberIdlePlans(cPlanAttack);
  370.  
  371.    if (numberIdleAttackPlans > 0)
  372.       return;
  373.  
  374.    //If we have enough unassigned military units, create a new attack plan.
  375.    int numberAvailableUnits=aiNumberUnassignedUnits(attackerUnitTypeID3);
  376.    aiEcho("There are "+numberAvailableUnits+" raiding cav available for a new attack.");
  377.    
  378.     if (numberAvailableUnits >= 4)
  379.         setupAttack(1);
  380. }
  381.  
  382. //==============================================================================
  383. // longhouseBuilt - called with an AI FUNC when he has one longhouse.
  384. //==============================================================================
  385. /*
  386. void longhouseBuilt( int parameter=-1 )
  387. {
  388.     vector gatherPointCavalry=kbGetBlockPosition("3126");
  389.  
  390.     //Maintain raiding cavalry.  Up to eight.
  391.    maintainPlan3ID=aiPlanCreate("Maintain 8 "+kbGetProtoUnitName(attackerUnitTypeID3), cPlanTrain);
  392.    if (maintainPlan3ID >= 0)
  393.    {
  394.         //Must set the type of unit to train.
  395.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanUnitType, 0, attackerUnitTypeID3);
  396.       //Set the number of units to maintain in the world at one time.
  397.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanNumberToMaintain, 0, 8);
  398.       //Don't train units faster than every 20 seconds
  399.       aiPlanSetVariableInt(maintainPlan3ID, cTrainPlanFrequency, 0, 20);
  400.       //Set a gather point.
  401.       aiPlanSetVariableVector(maintainPlan3ID, cTrainPlanGatherPoint, 0, gatherPointCavalry);
  402.       //Activate the plan.
  403.       aiPlanSetActive(maintainPlan3ID);
  404.    }
  405.  
  406.     // Time for lots more villagers.
  407.     aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 30);
  408.     
  409.     // Time for more ulfsarks.  Maintain ten now.
  410.     aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 10);
  411.  
  412.     // Change percentage of who's on what.
  413.    aiSetResourceGathererPercentage(cResourceFood, 0.6, false, cRGPScript);
  414.    aiSetResourceGathererPercentage(cResourceWood, 0.1, false, cRGPScript);
  415.    aiSetResourceGathererPercentage(cResourceGold, 0.3, false, cRGPScript);
  416.     aiNormalizeResourceGathererPercentages(cRGPScript);
  417.    
  418.     // Food resource breakdown now changes to almost entirely farms.
  419.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, 1, 10, 0.2, gMainBaseID);
  420.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHunt, 1, 10, 0.1, gMainBaseID);
  421.     aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 50, 0.7, gMainBaseID);
  422.  
  423.     // Research some techs.
  424.     createTechProgression(cTechHeavyInfantry, "Research Heavy Infantry", cUnitTypeLonghouse);
  425.     createTechProgression(cTechHeavyCavalry, "Research Heavy Cavalry", cUnitTypeLonghouse);
  426.     createTechProgression(cTechIrrigation, "Research Plow", cUnitTypeOxCart);
  427.  
  428.     // Progress to Huskarls - kind of a hack, used to get him to build a hill fort.
  429.     createUnitProgression(cUnitTypeHuskarl, "Progression to Huskarls");
  430.  
  431.     // Activate attacks.  Time to beat up on the player.
  432.     xsEnableRule("attackGenerator1");
  433. }
  434.  
  435. //==============================================================================
  436. // hillFortBuilt - called with an AI FUNC when he has one hill fort.
  437. //==============================================================================
  438. void hillFortBuilt( int parameter=-1 )
  439. {
  440.     vector gatherPointGiants=kbGetBlockPosition("3125");
  441.  
  442.     //Maintain a single mountain giant.  Adds to the fun.  :)
  443.    maintainPlan4ID=aiPlanCreate("Maintain 1 "+kbGetProtoUnitName(attackerUnitTypeID4), cPlanTrain);
  444.    if (maintainPlan4ID >= 0)
  445.    {
  446.         //Must set the type of unit to train.
  447.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanUnitType, 0, attackerUnitTypeID4);
  448.       //Set the number of units to maintain in the world at one time.
  449.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanNumberToMaintain, 0, 1);
  450.       //Don't train units faster than every 60 seconds
  451.       aiPlanSetVariableInt(maintainPlan4ID, cTrainPlanFrequency, 0, 60);
  452.       //Set a gather point.
  453.       aiPlanSetVariableVector(maintainPlan4ID, cTrainPlanGatherPoint, 0, gatherPointGiants);
  454.       //Activate the plan.
  455.       aiPlanSetActive(maintainPlan4ID);
  456.    }
  457.  
  458.     // Change percentage of who's on what.
  459.    aiSetResourceGathererPercentage(cResourceFood, 0.5, false, cRGPScript);
  460.    aiSetResourceGathererPercentage(cResourceWood, 0.1, false, cRGPScript);
  461.    aiSetResourceGathererPercentage(cResourceGold, 0.4, false, cRGPScript);
  462. }
  463. */
  464.  
  465. //==============================================================================
  466. // MAIN. 
  467. //==============================================================================
  468. void main(void)
  469. {
  470.    //Startup.
  471.    miscStartup();
  472.     initEcon();
  473.  
  474.    //Share a common gather point.
  475.    vector gatherPointMilitary=kbGetBlockPosition("2928");
  476.  
  477.     // Cheat up some favor.  It's tough to be Norse.
  478.     aiResourceCheat( 3, cResourceFavor, 45.0 );
  479.     
  480.    //Maintain villagers.  Fifteen should do it.
  481.     /*
  482.    maintainPlan1ID=aiPlanCreate("Maintain 15 "+kbGetProtoUnitName(attackerUnitTypeID1), cPlanTrain);
  483.    if (maintainPlan1ID >= 0)
  484.    {
  485.         //Must set the type of unit to train.
  486.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanUnitType, 0, attackerUnitTypeID1);
  487.       //You can limit the number of units that are ever trained by this plan with this call.
  488.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  489.       //Set the number of units to maintain in the world at one time.
  490.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanNumberToMaintain, 0, 12);
  491.       //Don't train units faster than every 15 seconds
  492.       aiPlanSetVariableInt(maintainPlan1ID, cTrainPlanFrequency, 0, 15);
  493.       //Set a gather point.
  494.       aiPlanSetVariableVector(maintainPlan1ID, cTrainPlanGatherPoint, 0, gatherPointVillager);
  495.       //Activate the plan.
  496.       aiPlanSetActive(maintainPlan1ID);
  497.    }
  498.     */
  499.  
  500.     //Maintain ulfsarks!
  501.    maintainPlan2ID=aiPlanCreate("Maintain 5 "+kbGetProtoUnitName(attackerUnitTypeID2), cPlanTrain);
  502.    if (maintainPlan2ID >= 0)
  503.    {
  504.         //Must set the type of unit to train.
  505.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanUnitType, 0, attackerUnitTypeID2);
  506.       //You can limit the number of units that are ever trained by this plan with this call.
  507.       //aiPlanSetVariableInt(maintainPlanID, cTrainPlanNumberToTrain, 0, 25);
  508.       //Set the number of units to maintain in the world at one time.
  509.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanNumberToMaintain, 0, 8);
  510.       //Don't train units faster than every 45 seconds 
  511.       aiPlanSetVariableInt(maintainPlan2ID, cTrainPlanFrequency, 0, 45);
  512.       //Set a gather point.
  513.       aiPlanSetVariableVector(maintainPlan2ID, cTrainPlanGatherPoint, 0, gatherPointMilitary);
  514.       //Activate the plan.
  515.       aiPlanSetActive(maintainPlan2ID);
  516.    }
  517.  
  518.     int exploreID1 = aiPlanCreate("Explore 1", cPlanExplore);
  519.     if(exploreID1 >= 0)
  520.    {
  521.       aiPlanAddUnitType(exploreID1, cUnitTypeRaven, 1, 1, 1);
  522.       aiPlanSetActive(exploreID1);
  523.    }
  524.    int exploreID2 = aiPlanCreate("Explore 2", cPlanExplore);
  525.    if(exploreID2 >= 0)
  526.    {
  527.       aiPlanAddUnitType(exploreID2, cUnitTypeRaven, 1, 1, 1);
  528.       aiPlanSetVariableBool(exploreID2, cExplorePlanDoLoops, 0, false);
  529.       aiPlanSetActive(exploreID2);
  530.    }
  531. }
  532.